<template>
  <div
    ref="wrapper"
    class="measure-device-container"
    :style="{
      '--marker-top': current_marker_top + 'px'
    }"
  >
    <el-tabs v-model="activeIndex" class="module menu" type="border-card">
      <el-tab-pane label="任务" name="1">
        <gantt-task
          :searchQuery="condition.number"
          @onGanttRefresh="onRefreshData"
          @onTaskAdd="onAddTask"
          @onExportGantt="onExportGanttFile"
          @onQueryChange="onSelectQueryChange"
        />
      </el-tab-pane>
      <el-tab-pane label="设置" name="2">
        <gantt-setting
          :grid-columns="editCell_zh"
          :cur-columns="curGridColumns"
          @grid-column-change="updateColumns"
          @grid-sort-change="updateSort"
          @zoom-change="updateScales"
        />
      </el-tab-pane>
      <el-tab-pane label="图例" name="3">
        <gantt-chart />
      </el-tab-pane>
    </el-tabs>
    <div ref="gantt" class="module gantt" />
    <div class="module pagination">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="condition.page"
        :page-sizes="[100, 200, 300, 400]"
        :page-size="condition.pageSize"
        background
        layout="total, sizes, prev, pager, next, jumper"
        :total="meters_total_num"
      />
    </div>
    <transition name="opacity">
      <div
        v-if="isLightBoxShow"
        class="lightbox"
        :style="{
          left: sidebar.opened ? '210px' : '54px'
        }"
      >
        <task-edit
          class="card"
          :edit-cell="editCell"
          :user-names="userNames"
          :edit-mode="lightboxEditMode"
          @confirm-light-box="onNewTaskConfirmed"
          @update-light-box="onTaskUpdated"
          @close-light-box="onLightBoxClose"
        />
      </div>
    </transition>
    <transition name="opacity">
      <div
        v-if="isNameplateShow"
        class="lightbox"
        :style="{
          left: sidebar.opened ? '210px' : '54px'
        }"
      >
        <TaskNameplate
          :meterNo="selectedNameplateNo"
          v-clickoutside="
            () => {
              isNameplateShow = false
            }
          "
        />
      </div>
    </transition>
    <el-button v-show="false" ref="serial" @click.native.prevent="handleSerial">
      串口连接
    </el-button>
  </div>
</template>

<script lang="ts">
import Vue, { ComponentInstance } from 'vue'
import { Component, Ref, Watch } from 'vue-property-decorator'
import { Getter } from 'vuex-class'
import { gantt } from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
// 组件
import GanttSetting from './compoents/GanttSetting.vue'
import GanttTask from './compoents/GanttTask.vue'
import GanttChart from './compoents/GanttChart.vue'
import TaskEdit from './compoents/TaskEdit.vue'
import TaskNameplate from './compoents/TaskNameplate.vue'
// 类型接口
import { Dictionary, SettingType } from '@/interface/Basic'
import { TaskCell } from './settings/interface'
import { SelectOptionsType } from '@/interface/ElementUI'
// data
import { order_settings } from './settings/basic'
// 方法
// import { serial } from '@/utils/navigator'
import { generateFileName } from '@/utils/file'
import {
  GetFuzzyTasks,
  AddMainTask,
  UpdateMainTask,
  GetNameplateData,
  GetDataByMeter
} from '@/api/dashboard'
import { AxiosResponse } from 'axios'
import { Message } from 'element-ui'
import { formatTime } from '@/utils/specificFunc'
interface ConditionType {
  page: number
  pageSize: number
  number: string
}
@Component({
  name: 'Dashboard',
  components: {
    GanttSetting,
    GanttTask,
    GanttChart,
    TaskEdit,
    TaskNameplate
  }
})
class Dashboard extends Vue {
  @Ref() readonly wrapper!: HTMLElement
  @Ref() readonly gantt!: HTMLElement
  @Ref() readonly serial!: ComponentInstance
  @Getter('name') username!: string
  @Getter('sidebar') sidebar!: { opened: boolean }
  @Getter('rolesList') rolesList!: Dictionary<Dictionary<string>>
  ui: Dictionary<number> = {
    clientHeight: 100
  }
  mode: 'write' | 'read' = 'write'
  // toolbox relative
  activeIndex = '1'
  activeItem = 'gantt-task'
  activeTab = 'order'
  curGridColumns: string[] = ['start_date', 'Sales_order', 'Production_order']
  // gantt relative
  ganttTimer: NodeJS.Timer | undefined = undefined
  ganttSelectedID = ''
  scrollPosition = {
    x: 0,
    y: 0
  }
  // lightbox relative
  isLightBoxShow = false
  lightboxEditMode: 'edit' | 'add' = 'edit'
  isPopupConfirm = false
  editCell: TaskCell = {
    id: 0,
    level: 0,
    meter: '',
    personName: '',
    progress: 0,
    description: '',
    start_date: '',
    end_date: '',
    status: '',
    relativeUsers: []
  }
  editCell_zh: Dictionary<string> = {
    id: 'ID',
    level: '任务级别',
    meter: '表编号',
    Operator: '操作人',
    progress: '进度',
    description: '任务描述',
    start_date: '开始日期',
    end_date: '结束日期',
    Sales_order: '销售订单号',
    Production_order: '生产订单号',
    Product_model: '产品型号',
    Pressure: '公称压力',
    Drift: '通径',
    status: '状态'
  }
  // 铭牌生成
  isNameplateShow: boolean = false
  selectedNameplateNo: string = ''
  // 操作表相关配置
  OrderSetting: SettingType[] = order_settings
  userNames: SelectOptionsType<string> = []
  // gantt
  tasks: {
    data: TaskCell[]
    links: any[]
  } = {
    data: [
      // {
      //   id: 4,
      //   meter: 'WA2-2',
      //   description: '子级流程描述1',
      //   level: 2,
      //   start_date: '10-11-2022',
      //   personName: '用户4',
      //   end_date: '15-11-2022',
      //   progress: 0,
      //   parent: 2,
      //   status: 'sub sub_yellow',
      //   relativeUsers: []
      // }
    ],
    links: [
      // { id: 1, source: 1, target: 2, type: '0' }
    ]
  }
  currentTask!: TaskCell
  hover_marker_id: string = ''
  current_marker_top: number = 0
  // pagination
  meters_total_num: number = 0
  condition: ConditionType = {
    page: 1,
    pageSize: 100,
    number: ''
  }
  shouldReconnect = false
  // 计算属性
  get EditCellTimeRange() {
    return [
      new Date(this.editCell.start_date).getTime(),
      new Date(this.editCell.end_date).getTime()
    ]
  }
  get HasEmitLimits() {
    const { AAF } = this.rolesList
    return AAF.AAF_0 !== '0'
  }
  @Watch('condition', { deep: true })
  condition_handler(newVal: ConditionType) {
    this.initData(newVal)
  }
  @Watch('sidebar.open')
  so_handler() {
    this.initGantt()
  }
  // 生命周期
  mounted() {
    this.$broadOn('reconnectComPort', () => {
      this.shouldReconnect = true
      // this.serial.$el.dispatchEvent(new MouseEvent('click'))
    })
    this.initGantt()
    window.addEventListener('resize', () => {
      gantt.render()
    })
    this.$nextTick(() => {
      this.createScript('https://export.dhtmlx.com/gantt/api.js')
    })
    // const s = document.createElement('script')
    // s.type = 'text/javascript'
    // s.src = 'https://export.dhtmlx.com/gantt/api.js'
    // document.body.appendChild(s)
  }
  beforeDestroy() {
    window.removeEventListener('resize', this.initGantt)
  }
  // 方法
  // dhtmlx 导出功能，第三方 script 代码导入
  createScript(url: string) {
    const scriptElement = document.createElement('script')
    scriptElement.src = url
    const headerElement = document.querySelector('head') as any
    if (headerElement) {
      headerElement.appendChild(scriptElement)
    }
  }
  computedWrapperSize() {
    const { clientHeight } = this.wrapper.parentElement!
    this.ui = { clientHeight }
  }
  generateTaskUsers() {
    const users = [this.username, '刘程', '方超']
    let str = ''
    users.forEach(name => {
      str += `<span class="iconfont">${name[0]}</span>`
    })
    return str
  }
  handleSizeChange(size: number) {
    this.condition.pageSize = size
  }
  handleCurrentChange(page: number) {
    this.condition.page = page
  }
  // gantt 初始化
  async initGantt() {
    const _this = this
    // plugin
    gantt.plugins({
      marker: true
    })
    // 单击事件
    gantt.attachEvent(
      'onTaskClick',
      function (id, e) {
        // 获取选中 task 的详细信息
        gantt.selectTask(id)
        // const data = _this.tasks.data
        const task_instance = gantt.getTask(id)
        // const task = data[data.findIndex(item => item.id === Number(id))]
        _this.currentTask = task_instance
        // 滚动到任务的起始位置
        const { start_date, end_date } = task_instance
        const { left } = gantt.getTaskPosition(task_instance, start_date, end_date)
        let { x: start } = gantt.getScrollState()
        if (start < left) {
          clearInterval(_this.ganttTimer)
          _this.ganttTimer = setInterval(() => {
            if (start <= left) {
              start += 100
              gantt.scrollTo(start > left ? left : start, null)
            }
          }, 10)
        } else {
          clearInterval(_this.ganttTimer)
          _this.ganttTimer = setInterval(() => {
            if (start >= left) {
              start -= 100
              gantt.scrollTo(start < left ? left : start, null)
            }
          }, 10)
        }
        // 判断点击区域
        const { className } = e.target
        const isClickTreeIcon = className.indexOf('gantt_tree_icon') !== -1
        const isClickIconCopy = className.indexOf('icon-template') !== -1
        const isClickIconTemplate = className.indexOf('icon-nameplate') !== -1
        const isOpen = className.indexOf('gantt_open') !== -1
        const isClose = className.indexOf('gantt_close') !== -1
        if (isClickIconCopy) {
          _this.$set(_this.condition, 'number', id)
          return
        }
        if (isClickIconTemplate) {
          _this.handleNameplate(id)
          return
        }
        if (isClickTreeIcon) {
          if (isOpen) gantt.open(id)
          else if (isClose) gantt.close(id)
        }
      },
      {}
    )
    // 双击事件
    gantt.attachEvent(
      'onTaskDblClick',
      function (id) {
        gantt.selectTask(id)
        gantt.showLightbox(id)
        const { x, y } = gantt.getScrollState()
        _this.scrollPosition = { x, y }
        _this.ganttSelectedID = id
      },
      {}
    )
    gantt.showLightbox = function (id) {
      const task = gantt.getTask(id)
      _this.editCell = { ...task }
      _this.isLightBoxShow = true
      _this.lightboxEditMode = 'edit'
    }
    // 鼠标悬停事件
    gantt.attachEvent(
      'onMouseMove',
      function (id) {
        if (!id) {
          gantt.deleteMarker(_this.hover_marker_id)
          _this.hover_marker_id = ''
          return
        }
        if (_this.hover_marker_id) gantt.deleteMarker(_this.hover_marker_id)
        const curTask = gantt.getTask(id)
        const { start_date, end_date } = curTask
        const { top } = gantt.getTaskPosition(curTask, start_date, end_date)
        _this.current_marker_top = top
        _this.hover_marker_id = gantt.addMarker({
          start_date,
          css: 'today',
          text: new Date(start_date).toLocaleDateString().replaceAll('/', '-')
        })
      },
      {}
    )
    // 时间线拖拽事件
    gantt.attachEvent('onAfterTaskDrag', _this.onTaskTimelineChange, {})
    // timeline-scale grid
    gantt.config.scale_height = 50
    gantt.config.row_height = 40
    // gantt.config.grid_elastic_columns = false
    gantt.config.layout = {
      css: 'gantt_container',
      cols: [
        {
          width: 400,
          min_width: 300,
          rows: [
            { view: 'grid', id: 'grid', scrollY: 'scrollVer', scrollX: 'scrollGridHor' },
            { view: 'scrollbar', id: 'scrollGridHor' }
          ]
        },
        {
          rows: [
            { view: 'timeline', id: 'timeline', scrollX: 'scrollHor', scrollY: 'scrollVer' },
            { view: 'scrollbar', id: 'scrollHor' }
          ]
        },
        { view: 'scrollbar', id: 'scrollVer' }
      ]
    }
    // 只读模式
    gantt.config.readonly = false
    gantt.config.details_on_dblclick = true
    gantt.config.drag_progress = false
    gantt.config.drag_move = false
    gantt.config.drag_links = false
    // 是否支持拖拽修改任务周期
    gantt.config.drag_resize = this.HasEmitLimits
    gantt.config.autosize = false
    // timeline scale top row
    gantt.config.show_task_cells = true
    gantt.config.show_grid = true
    gantt.config.date_format = '%Y-%m-%d'
    gantt.i18n.setLocale('cn')
    gantt.config.scroll_on_click = false
    // template
    // <div class='icons-container'>
    // ${_this.generateTaskUsers()}
    // </div>
    // 项目负责人：${task.personName}
    gantt.templates.task_text = function (start, end, task: TaskCell) {
      return `
        <div class='task-content'>
          <div class='task-text'>
            <span>表号：${task.meter}</span>
          </div>
        </div>
      `
    }
    gantt.templates.task_class = function (start, end, task: TaskCell) {
      return task.level === 1 ? 'firstLevelTask' : 'secondLevelTask'
    }
    this.updateColumns(this.curGridColumns)
    let default_zoom: 'day' | 'week' | 'month' | 'year' = 'week'
    const dashboardSetting = localStorage.getItem('pcls-prefer-daskboard-confirguration')
    if (dashboardSetting && JSON.parse(dashboardSetting).grid_setting) {
      const { active_zoom } = JSON.parse(dashboardSetting).grid_setting
      default_zoom = active_zoom
    }
    this.updateScales(default_zoom)
    this.initData(this.condition)
  }
  initData(newVal: ConditionType) {
    const mapColor: Dictionary<string> = {
      red: 'rgb(247, 92, 76)',
      green: 'rgb(30, 188, 97)',
      blue: 'rgb(2, 135, 208)',
      yellow: 'rgb(215, 210, 30)',
      grey: 'rgb(175, 175, 175)',
      purple: 'rgb(142, 68, 173)'
    }
    GetFuzzyTasks(newVal).then(
      (res: AxiosResponse<{ ReturnData: { count: number; meters: TaskCell[] } }>) => {
        const { meters, count } = res.data.ReturnData
        const { page, pageSize } = newVal
        this.meters_total_num = count
        const data = meters.map((current, index) => {
          current.start_date = new Date(current.start_date)
            .toLocaleDateString()
            .replaceAll('/', '-')
          current.end_date = new Date(current.end_date).toLocaleDateString().replaceAll('/', '-')
          return Object.assign({}, current, {
            id: current.meter,
            index: index + 1,
            level: 1,
            status: 'parent',
            color: mapColor[current.color ? current.color : 'blue']
          })
        })
        this.tasks.data = data
        gantt.clearAll()
        gantt.init(this.gantt)
        gantt.parse(
          {
            data,
            links: []
          },
          'json'
        )
        if (count < page * pageSize) {
          this.$set(this.condition, 'page', Math.floor(count / pageSize) + 1)
        }
      }
    )
  }
  // menu relative
  handleMenuSelect(index: string) {
    // if (index[0] === '1') {
    //   this.activeIndex = '2'
    //   return
    // }
    const mapComponent: {
      [key: string]: string
    } = {
      '1': 'gantt-task',
      '2': 'gantt-setting'
    }
    this.activeItem = mapComponent[index]
  }
  // lightbox relative
  // 确认新增任务
  onNewTaskConfirmed(data: Dictionary<string>[]) {
    if (data.some(item => item.AAF001 === '' || !item.AAF001)) {
      Message({
        type: 'warning',
        message: '表号为必填项，不能为空'
      })
      return
    }
    AddMainTask(data).then((res: AxiosResponse<{ Message: string }>) => {
      const { Message: message } = res.data
      Message({
        type: 'success',
        message
      })
      this.isLightBoxShow = false
      this.initData(this.condition)
    })
  }
  onTaskUpdated(data: Dictionary<string>) {
    UpdateMainTask(data).then((res: AxiosResponse<{ Message: string }>) => {
      const { Message: message } = res.data
      Message({
        type: 'success',
        message
      })
      this.isLightBoxShow = false
      this.initData(this.condition)
    })
  }
  onLightBoxClose() {
    this.initGantt()
    this.isLightBoxShow = false
    setTimeout(() => {
      const { x, y } = this.scrollPosition
      gantt.scrollTo(x, y)
      gantt.selectTask(this.ganttSelectedID)
    }, 500)
  }
  // nameplate relative
  handleNameplate(id: string) {
    interface ResponseType {
      Message: string
      ReturnData: Dictionary<string>[]
    }
    GetNameplateData({ ManufacturingNO: id }).then((res: AxiosResponse<ResponseType>) => {
      const { Message, ReturnData } = res.data
      if (ReturnData.length === 0) {
        this.$message({
          type: 'error',
          message: Message
        })
        return
      } else {
        this.isNameplateShow = true
        this.selectedNameplateNo = id
      }
    })
  }
  // gantt-task 响应函数
  onExportGanttFile(type: string) {
    if (type === 'excel') return
    switch (type) {
      case 'png':
        gantt.exportToPNG({ name: generateFileName('gantt', '.png') })
        // exportScreenshot(this.gantt, generateFileName('png'))
        break
      case 'pdf':
        gantt.exportToPDF({ name: generateFileName('gantt', 'pdf') })
        break
      default:
        gantt.exportToExcel({
          name: generateFileName('', 'xlsx')
        })
        break
    }
  }
  onSelectQueryChange(query: string) {
    this.condition.number = query
  }
  onAddTask() {
    this.isLightBoxShow = true
    this.lightboxEditMode = 'add'
    this.editCell = {
      id: '',
      level: 0,
      progress: 0,
      meter: '',
      start_date: '',
      end_date: '',
      relativeUsers: []
    }
  }
  onTaskTimelineChange(id: string) {
    GetDataByMeter(id).then((res: AxiosResponse<{ ReturnData: Dictionary<string> }>) => {
      const { ReturnData } = res.data
      console.log(ReturnData, gantt.getTask(id))
      const { start_date, end_date } = gantt.getTask(id)
      ReturnData.AAF2401 = formatTime(new Date(start_date).getTime(), 'YYYY-MM-DD-hh-mm-ss')
      ReturnData.AAF2301 = formatTime(new Date(end_date).getTime(), 'YYYY-MM-DD-hh-mm-ss')
      UpdateMainTask(ReturnData).then(res => {
        console.log(res)
      })
    })
  }
  onRefreshData() {
    this.condition = {
      page: 1,
      pageSize: 100,
      number: ''
    }
    this.initGantt()
  }
  // gantt-setting 响应函数
  updateColumns(columns: string[]) {
    if (columns.length === 0) return
    const defaultColumn = [
      {
        name: 'index',
        label: '',
        width: 40,
        align: 'center'
      },
      {
        name: 'meter',
        label: '表编号',
        tree: true,
        width: 220,
        align: 'left',
        template: function (obj: any) {
          return `
          <div class='grid-column_meter'>
            <div class="column-content">
              <span>${obj.meter}</span>
              <div class="column-icons">
                <i class="iconfont icon-template"></i>
                <i class="iconfont icon-nameplate"></i>
              </div>
            </div>
          </div>
        `
        },
        onrender: function (task: any, node: any) {
          node.setAttribute('class', 'gantt_cell gantt_last_cell gantt_cell_tree ' + task.status)
        }
      }
    ]
    const mapColumns = columns.map(column => {
      if (column !== 'meter') {
        return {
          name: column,
          label: this.editCell_zh[column],
          width: 90,
          align: 'center'
        }
      }
    })
    gantt.config.layout = {
      css: 'gantt_container',
      cols: [
        {
          width: [...defaultColumn].length * 100 + [...mapColumns].length * 90,
          min_width: 300,
          rows: [
            { view: 'grid', id: 'grid', scrollY: 'scrollVer', scrollX: 'scrollGridHor' },
            { view: 'scrollbar', id: 'scrollGridHor' }
          ]
        },
        {
          rows: [
            { view: 'timeline', id: 'timeline', scrollX: 'scrollHor', scrollY: 'scrollVer' },
            { view: 'scrollbar', id: 'scrollHor' }
          ]
        },
        { view: 'scrollbar', id: 'scrollVer' }
      ]
    }
    this.curGridColumns = columns
    gantt.config.columns = [...defaultColumn, ...mapColumns]
    gantt.init(this.gantt)
    gantt.parse(this.tasks)
  }
  updateScales(zoom: 'day' | 'week' | 'month' | 'year') {
    function weekScaleTemplate(date: Date) {
      const weekNum = gantt.date.date_to_str('第 %W 周')
      return weekNum(date)
    }
    function yearMonthScaleTemplate(date: Date) {
      const year_month = gantt.date.date_to_str('%Y年%m月')
      return year_month(date)
    }
    function yearScaleTemplate(date: Date) {
      const year = gantt.date.date_to_str('%Y年')
      return year(date)
    }
    function monthScaleTemplate(date: Date) {
      const month = gantt.date.date_to_str('%m月')
      return month(date)
    }
    if (zoom === 'day') {
      gantt.config.scales = [
        {
          unit: 'month',
          step: 1,
          template: yearMonthScaleTemplate
        },
        {
          unit: 'day',
          step: 1,
          date: '%d',
          css: function (date: Date) {
            if (!gantt.isWorkTime({ date, unit: 'day' })) {
              return 'weekend'
            }
          }
        }
      ]
    } else if (zoom === 'week') {
      gantt.config.scales = [
        {
          unit: 'month',
          step: 1,
          template: yearMonthScaleTemplate
        },
        {
          unit: 'week',
          step: 1,
          template: weekScaleTemplate
        }
      ]
    } else if (zoom === 'month') {
      gantt.config.scales = [
        {
          unit: 'year',
          step: 1,
          template: yearScaleTemplate
        },
        {
          unit: 'month',
          step: 1,
          template: monthScaleTemplate
        }
      ]
    } else {
      gantt.config.scales = [
        {
          unit: 'year',
          step: 1,
          template: yearScaleTemplate
        }
      ]
    }
    gantt.init(this.gantt)
  }
  updateSort(sort: string) {
    console.log(sort)
  }
  async handleSerial() {
    // const result = await serial(this.shouldReconnect)
    // this.shouldReconnect = false
    // this.serial.$el.dispatchEvent(new MouseEvent('click'))
    // serial().then(res => {
    //   console.log(res)
    // })
  }
  // 暂无用处的函数
  deleteTask() {
    this.isPopupConfirm = false
    gantt.deleteTask(this.editCell.id)
    this.isLightBoxShow = false
  }
}
export default Dashboard
</script>

<style lang="less" scoped>
@import '~@/styles/theme.less';
@import '~@/styles/layout.less';
@import '~@/styles/variable.less';
.measure-device-container {
  box-sizing: border-box;
  height: calc(100vh - 50px);
  width: 100%;
  padding: 20px;
  padding-top: 10px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  #color(background-color, --primary-bg-color);
  .module {
    width: 100%;
    transition: all 0.5s ease;
    #color(background-color, --module-bg-color);
    #shadow-color(0, 0, 4px, 0, --primary-shadow-color);
  }
  .menu {
    box-sizing: border-box;
    padding: 5px;
    margin-bottom: 15px;
    display: flex;
    flex-direction: column;
    /deep/.el-tabs__header {
      margin-bottom: 5px;
      .el-tabs__item {
        height: 30px;
        line-height: 30px;
      }
    }
    /deep/.el-tabs__content {
      height: 50px;
      padding: 0;
      .el-tab-pane {
        height: 100%;
      }
    }
  }
  .gantt {
    flex: 1;
    margin-bottom: 15px;
    /deep/.gantt_layout_root {
      border: none;
      .gantt_layout {
        // 左侧任务级联列表
        #color(background-color, --module-bg-color);
        .grid_cell {
          .gantt_layout_content {
            .gantt_grid {
              .gantt_grid_scale {
                #color(border-bottom-color, --lighter-border-color);
                .gantt_grid_head_cell {
                  font-family: 'Noto Sans Display', sans-serif;
                  border-left: solid 1px !important;
                  #color(color, --primary-text-color);
                  #color(background-color, --module-lighter-bg-color);
                  #color(border-left-color, --lighter-border-color) !important;
                }
                .gantt_grid_head_cell:first-child {
                  text-align: left;
                  padding-left: 30px;
                  border-left: none;
                }
              }
              .gantt_grid_data {
                .gantt_row {
                  #color(border-bottom-color, --lighter-border-color);
                  .gantt_cell {
                    font-size: 12px;
                    border-left: solid 1px !important;
                    #color(color, --primary-text-color);
                    #color(border-left-color, --lighter-border-color) !important;
                  }
                  .gantt_cell:first-child {
                    border-left: none;
                  }
                }
              }
            }
          }
          .gantt_grid_scale {
            // border: none !important;
            .gantt_grid_head_cell {
              border-left: solid 1px !important;
              #color(border-left-color, --lighter-border-color) !important;
            }
            .gantt_grid_head_cell:first-child {
              text-align: left;
              padding-left: 30px;
              border-left: none;
            }
          }
          .gantt_grid_data {
            .gantt_row {
              cursor: pointer;
              #color(background-color, --module-bg-color);
              .gantt_cell {
                #flex(row, center, space-between);
                .gantt_tree_icon {
                  &.gantt_folder_open {
                    background-size: 18px;
                    background-image: url(../../assets/icon/open.png) !important;
                  }
                  &.gantt_folder_closed {
                    background-size: 18px;
                    background-image: url(../../assets/icon/close.png) !important;
                  }
                }
                .gantt_tree_content {
                  flex: 1;
                  .grid-column_meter {
                    .column-content {
                      #flex(row, center, space-between);
                      span {
                        display: inline-block;
                        flex: 1;
                      }
                      i {
                        display: block;
                        box-sizing: border-box;
                        padding: 2px;
                        line-height: 20px;
                        transition: all 0.2s ease;
                      }
                      i:hover {
                        border-radius: 2px;
                        color: #ffffff;
                        #color(background-color, --primary-blue-color);
                      }
                      .column-icons {
                        width: 40px;
                        #flex(row, center, space-between);
                      }
                    }
                  }
                }
              }
              .parent {
                .gantt_tree_icon {
                  &.gantt_file {
                    background-size: 18px;
                    background-image: url(../../assets/icon/close.png) !important;
                  }
                  &.gantt_folder_open {
                    background-size: 18px;
                    background-image: url(../../assets/icon/open.png) !important;
                  }
                  &.gantt_folder_closed {
                    background-size: 18px;
                    background-image: url(../../assets/icon/close.png) !important;
                  }
                }
              }
              .sub {
                .gantt_tree_icon.gantt_file {
                  background: none;
                  position: relative;
                  &::before {
                    content: '';
                    width: 15px;
                    height: 15px;
                    border-radius: 50%;
                    position: absolute;
                    left: 50%;
                    top: 50%;
                    transform: translate(-50%, -50%);
                  }
                }
              }
              .sub_yellow {
                .gantt_tree_icon.gantt_file {
                  &::before {
                    #color(background-color, --primary-yellow-color);
                  }
                }
              }
            }
            .gantt_row:hover {
              #color(background-color, --gray-blue-color);
            }
            .gantt_selected {
              #color(background-color, --module-bg-color);
            }
          }
          ::-webkit-scrollbar {
            width: 0;
            height: 0;
          }
        }
        // 右侧时间线列表
        .timeline_cell {
          .gantt_layout_content {
            .gantt_task {
              .gantt_task_scale {
                #color(border-bottom-color, --lighter-border-color);
                .gantt_scale_line {
                  #color(border-top-color, --lighter-border-color);
                  #color(background-color, --module-lighter-bg-color);
                  .gantt_scale_cell {
                    #color(color, --primary-text-color);
                    #color(border-right-color, --lighter-border-color);
                  }
                }
              }
              .gantt_data_area {
                .gantt_task_bg {
                  .gantt_task_row {
                    #color(border-bottom-color, --lighter-border-color);
                    #color(background-color, --module-bg-color);
                    .gantt_task_cell {
                      #color(border-right-color, --lighter-border-color);
                    }
                  }
                  .gantt_selected {
                    #color(background-color, --gray-blue-color);
                  }
                }
                .gantt_bars_area {
                  .firstLevelTask {
                    border: none;
                  }
                  .secondLevelTask {
                    border: none;
                  }
                  .gantt_task_line {
                    .gantt_task_progress_wrapper {
                      .gantt_task_progress {
                        opacity: 0.2;
                        background-color: rgba(255, 255, 255, 0);
                        background-image: repeating-linear-gradient(
                          135deg,
                          transparent,
                          transparent 10px,
                          rgba(255, 255, 255, 1) 10px,
                          rgba(255, 255, 255, 1) 20px
                        );
                      }
                    }
                    .gantt_task_content {
                      .task-content {
                        position: relative;
                        box-sizing: border-box;
                        padding-left: 20px;
                        width: 100%;
                        display: flex;
                        align-items: center;
                        justify-content: flex-start;
                      }
                      .icons-container {
                        position: absolute;
                        left: 10px;
                        display: flex;
                        flex-direction: row-reverse;
                        align-items: center;
                        text-align: center;
                        .iconfont {
                          box-sizing: border-box;
                          display: inline-block;
                          position: relative;
                          width: 20px;
                          height: 20px;
                          margin-left: -10px;
                          text-align: center;
                          line-height: 20px;
                          border-radius: 50%;
                          opacity: 1;
                          font-size: 12px;
                          color: #ffffff;
                          #color(background-color, --primary-blue-color);
                          #shadow-color(0, 0, 4px, 0, --primary-shadow-color);
                        }
                        .iconfont:last-child {
                          margin-left: 0;
                        }
                      }
                    }
                  }
                }
                .gantt_marker_area {
                  .today {
                    #color(background-color, --primary-green-color);
                    .gantt_marker_content {
                      top: var(--marker-top);
                    }
                  }
                }
              }
            }
          }
        }
        // 底部滚动条样式
        .scrollHor_cell {
          .gantt_layout_content {
            color: red;
          }
        }
      }
      .gantt_layout_cell_border_right {
        #color(border-right-color, --lighter-border-color);
      }
    }
  }
  .pagination {
    box-sizing: border-box;
    padding: 5px;
    #flex(row, center, flex-start);
  }
  .test_button_groups {
    display: flex;
    align-items: center;
    justify-content: flex-start;
  }
  .lightbox {
    position: fixed;
    top: 0;
    bottom: 0;
    left: @sidebarWidth;
    right: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.2);
  }
  .table-container {
    width: 80%;
    height: 100%;
    background-color: #ffffff;
    .el-table {
      height: 100%;
      max-height: 100%;
    }
  }
  .toolbox-container {
    flex: 1;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
  }
}
.opacity-enter-active,
.opacity-leave-active {
  transition: all 0.5s ease;
}
.opacity-enter,
.opacity-leave-to {
  opacity: 0;
}
.opacity-enter-to,
.opacity-leave {
  opacity: 1;
}
/deep/::-webkit-scrollbar {
  width: 10px;
  height: 10px;
  cursor: grab;
}
/deep/::-webkit-scrollbar-thumb {
  border-radius: 2px;
  transition: all 0.2s ease;
  #color(background-color, --primary-border-color);
}
/deep/::-webkit-scrollbar-thumb:hover {
  background-color: #8f9098;
}
</style>
